#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "../../include/graph.h"

#define            STRSIZ                2

static void print_graph(const graph_t *graph)
{

	int idx, j;
	set_t *adjacent;
	list_node_t *vlist, *member;
	
	fprintf(stdout, "vertices = %d, edges = %d\n", graph_vcount(graph), graph_ecount(graph));

	idx = 0;
	vlist = list_head(&graph_adlists(graph));

	while (idx < list_size(&graph_adlists(graph)))
	{
		fprintf(stdout, "graph[%d] = %s ", idx, (char *)((adjlist_t *)list_data(vlist))->vertex);
		j = 0;
		adjacent = &((adjlist_t *)list_data(vlist))->adjacent;
		member = list_head(adjacent);
		while (j < list_size(adjacent))
		{
			if (j > 0)
				fprintf(stdout, ", ");

			fprintf(stdout, "%s", (char *)list_data(member));
			member = list_next(member);
			j++;
		}

		idx++;
		fprintf(stdout, "\n");
		vlist = list_next(vlist);
	}

	return;
}


static int match_str(const void *str1, const void *str2)
{
	return !strcmp((const char *)str1, (const char *)str2);
}


int main(int argc, char *argv[])
{
	char               *data, data1[STRSIZ], *data2;
	graph_t graph;
	adjlist_t	*adjlist;
	int retval;

	graph_init(&graph, match_str, free);

	if ((data = (char *)malloc(STRSIZ)) == NULL)
   		return 1;

	strcpy(data, "a");
	fprintf(stdout, "Inserting vertex %s\n", data);

	if (graph_insert_vertex(&graph, data) != 0)
	   return 1;

	if ((data = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data, "b");
	fprintf(stdout, "Inserting vertex %s\n", data);

	if (graph_insert_vertex(&graph, data) != 0)
	   return 1;

	if ((data = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data, "c");
	fprintf(stdout, "Inserting vertex %s\n", data);

	if (graph_insert_vertex(&graph, data) != 0)
	   return 1;

	if ((data = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data, "d");
	fprintf(stdout, "Inserting vertex %s\n", data);

	if (graph_insert_vertex(&graph, data) != 0)
	   return 1;

	if ((data = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data, "e");
	fprintf(stdout, "Inserting vertex %s\n", data);

	if (graph_insert_vertex(&graph, data) != 0)
	   return 1;
	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
		return 1;

	strcpy(data1, "a");
	strcpy(data2, "b");
	fprintf(stdout, "Inserting edge %s to %s\n", data1, data2);

	if (graph_insert_edge(&graph, data1, data2) != 0)
	   return 1;
	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
   		return 1;

	strcpy(data1, "a");
	strcpy(data2, "c");
	fprintf(stdout, "Inserting edge %s to %s\n", data1, data2);

	if (graph_insert_edge(&graph, data1, data2) != 0)
	   return 1;
	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
   		return 1;

	strcpy(data1, "b");
	strcpy(data2, "c");
	fprintf(stdout, "Inserting edge %s to %s\n", data1, data2);

	if (graph_insert_edge(&graph, data1, data2) != 0)
	   return 1;
	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
   return 1;

	strcpy(data1, "b");
	strcpy(data2, "d");
	fprintf(stdout, "Inserting edge %s to %s\n", data1, data2);

	if (graph_insert_edge(&graph, data1, data2) != 0)
	   return 1;

	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data1, "c");
	strcpy(data2, "b");
	fprintf(stdout, "Inserting edge %s to %s\n", data1, data2);

	if (graph_insert_edge(&graph, data1, data2) != 0)
	   return 1;

	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data1, "c");
	strcpy(data2, "c");
	fprintf(stdout, "Inserting edge %s to %s\n", data1, data2);

	if (graph_insert_edge(&graph, data1, data2) != 0)
	   return 1;

	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data1, "c");
	strcpy(data2, "d");
	fprintf(stdout, "Inserting edge %s to %s\n", data1, data2);

	if (graph_insert_edge(&graph, data1, data2) != 0)
	   return 1;

	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data1, "d");
	strcpy(data2, "a");
	fprintf(stdout, "Inserting edge %s to %s\n", data1, data2);

	if (graph_insert_edge(&graph, data1, data2) != 0)
	   return 1;

	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data1, "e");
	strcpy(data2, "c");
	fprintf(stdout, "Inserting edge %s to %s\n", data1, data2);

	if (graph_insert_edge(&graph, data1, data2) != 0)
	   return 1;
	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
   		return 1;

	strcpy(data1, "e");
	strcpy(data2, "d");
	fprintf(stdout, "Inserting edge %s to %s\n", data1, data2);

	if (graph_insert_edge(&graph, data1, data2) != 0)
	   return 1;

	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data1, "a");
	strcpy(data2, "c");
	data = data2;

	fprintf(stdout, "Removing edge %s to %s\n", data1, data2);

	if (graph_remove_edge(&graph, data1, (void **)&data) != 0)
	   return 1;

	free(data);
	print_graph(&graph);

	strcpy(data1, "c");
	strcpy(data2, "c");
	data = data2;

	fprintf(stdout, "Removing edge %s to %s\n", data1, data2);

	if (graph_remove_edge(&graph, data1, (void **)&data) != 0)
	   return 1;

	free(data);
	print_graph(&graph);

	strcpy(data1, "e");
	strcpy(data2, "c");
	data = data2;

	fprintf(stdout, "Removing edge %s to %s\n", data1, data2);

	if (graph_remove_edge(&graph, data1, (void **)&data) != 0)
	   return 1;

	free(data);
	print_graph(&graph);

	strcpy(data1, "a");
	strcpy(data2, "b");
	data = data2;

	fprintf(stdout, "Removing edge %s to %s\n", data1, data2);

	if (graph_remove_edge(&graph, data1, (void **)&data) != 0)
	   return 1;

	free(data);
	print_graph(&graph);

	strcpy(data1, "d");
	strcpy(data2, "a");
	data = data2;

	fprintf(stdout, "Removing edge %s to %s\n", data1, data2);

	if (graph_remove_edge(&graph, data1, (void **)&data) != 0)
	   return 1;

	free(data);
	print_graph(&graph);

	free(data2);

	strcpy(data1, "a");
	data = data1;

	fprintf(stdout, "Removing vertex %s\n", data1);

	if (graph_remove_vertex(&graph, (void **)&data) != 0)
	   return 1;

	free(data);
	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
   		return 1;

	strcpy(data1, "f");
	strcpy(data2, "a");

	retval = graph_insert_edge(&graph, data1, data2);
	fprintf(stdout,"Inserting an invalid edge from %s to %s...Value=%d (-1=OK)\n",
	   data1, data2, retval);

	if (retval != 0)
	   free(data2);

	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
		return 1;

	strcpy(data1, "c");
	strcpy(data2, "b");

	retval = graph_insert_edge(&graph, data1, data2);
	fprintf(stdout,"Inserting an existing edge from %s to %s...Value=%d (1=OK)\n",
	   data1, data2, retval);

	if (retval != 0)
	   free(data2);

	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
   		return 1;

	strcpy(data1, "f");
	strcpy(data2, "a");
	data = data2;

	retval = graph_remove_edge(&graph, data1, (void **)&data);
	fprintf(stdout, "Removing an invalid edge from %s to %s...Value=%d (-1=OK)\n",
	   data1, data2, retval);

	if (retval == 0)
   		free(data);

   	free(data2);
	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data1, "c");
	strcpy(data2, "e");
	data = data2;

	retval = graph_remove_edge(&graph, data1, (void **)&data);
	fprintf(stdout, "Removing an invalid edge from %s to %s...Value=%d (-1=OK)\n",
	   data1, data2, retval);

	if (retval == 0)
	   free(data);

	free(data2);
	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data2, "c");

	retval = graph_insert_vertex(&graph, data2);
	fprintf(stdout, "Inserting an existing vertex %s...Value=%d (1=OK)\n", data1,
	   retval);

	if (retval != 0)
	   free(data2);

	print_graph(&graph);

	if ((data2 = (char *)malloc(STRSIZ)) == NULL)
	   return 1;

	strcpy(data1, "b");
	strcpy(data2, "d");

	retval = graph_is_adjacent(&graph, data1, data2);
	fprintf(stdout, "Testing graph_is_adjacent (%s, %s)...Value=%d (1=OK)\n",
	   data1, data2, retval);

	strcpy(data1, "a");
	strcpy(data2, "e");

	retval = graph_is_adjacent(&graph, data1, data2);
	fprintf(stdout, "Testing graph_is_adjacent (%s, %s)...Value=%d (0=OK)\n",
	   data1, data2, retval);

	strcpy(data1, "e");
	strcpy(data2, "d");

	retval = graph_is_adjacent(&graph, data1, data2);
	fprintf(stdout, "Testing graph_is_adjacent (%s, %s)...Value=%d (1=OK)\n",
	   data1, data2, retval);

	strcpy(data1, "c");
	strcpy(data2, "a");

	retval = graph_is_adjacent(&graph, data1, data2);
	fprintf(stdout, "Testing graph_is_adjacent (%s, %s)...Value=%d (0=OK)\n",
	   data1, data2, retval);

	free(data2);

	strcpy(data1, "c");

	if (graph_adjlist(&graph, data1, &adjlist) != 0)
	   return 1;

	fprintf(stdout, "Vertices adjacent to %s: ", data1);

	int i = 0;
	int size = set_size(&adjlist->adjacent);
	list_node_t *element = list_head(&adjlist->adjacent);

	while (i < size) {

	   i++;
	   if (i > 1) fprintf(stdout, ", ");
	   fprintf(stdout, "%s", (char *)list_data(element));
	   element = list_next(element);

	}

	fprintf(stdout, "\n");

	fprintf(stdout, "Destroying the graph\n");
	graph_destroy(&graph);

	return 0;
}
